using System.Collections.Generic;
using System.Threading.Tasks;
using ExamKing.Application.Consts;
using ExamKing.Application.ErrorCodes;
using ExamKing.Application.Mappers;
using ExamKing.Application.Services;
using ExamKing.Core.Utils;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;

namespace ExamKing.WebApp.Teacher
{
    /// <summary>
    /// 试卷接口
    /// </summary>
    public class ExamController : ApiControllerBase
    {
        private readonly IExamService _examService;
        private readonly IQuestionService _questionService;
        private readonly ISelectService _selectService;
        private readonly IJudgeService _judgeService;

        /// <summary>
        /// 依赖注入 
        /// </summary>
        public ExamController(
            IExamService examService,
            IQuestionService questionService, 
            IJudgeService judgeService,
            ISelectService selectService)
        {
            _examService = examService;
            _questionService = questionService;
            _judgeService = judgeService;
            _selectService = selectService;
        }

        /// <summary>
        /// 手动组卷
        /// </summary>
        /// <param name="addExamInput"></param>
        /// <returns></returns>
        public async Task<ExamOutput> InsertAddExam(AddExamInput addExamInput)
        {
            var teacher = await GetTeacher();
            var addExamDto = addExamInput.Adapt<ExamDto>();
            addExamDto.TeacherId = teacher.Id;
            var questions = new List<ExamquestionDto>();
            foreach (var item in addExamInput.Selects)
            {
                var q = item.Adapt<ExamquestionDto>();
                q.QuestionType = QuestionTypeConst.Select;
                questions.Add(q);
            }

            foreach (var item in addExamInput.Singles)
            {
                var q = item.Adapt<ExamquestionDto>();
                q.QuestionType = QuestionTypeConst.Single;
                questions.Add(q);
            }

            foreach (var item in addExamInput.Judges)
            {
                var q = item.Adapt<ExamquestionDto>();
                q.QuestionType = QuestionTypeConst.Judge;
                questions.Add(q);
            }
            addExamDto.Examquestions = questions;
            
            var exam = await _examService.CreateExam(addExamDto);
            return exam.Adapt<ExamOutput>();
        }

        /// <summary>
        /// 自动组卷
        /// </summary>
        /// <param name="addExamInput"></param>
        /// <returns></returns>
        public async Task<ExamOutput> InsertAutoAddExam(AddAutoExamInput addExamInput)
        {
            var teacher = await GetTeacher();
            var addExamDto = new ExamDto();
            addExamDto.TeacherId = teacher.Id;
            addExamDto.ExamName = addExamInput.ExamName;
            addExamDto.StartTime = addExamInput.StartTime;
            addExamDto.EndTime = addExamInput.EndTime;
            addExamDto.Duration = addExamInput.Duration;
            addExamDto.CourseId = addExamInput.CourseId;

            var questions = new List<ExamquestionDto>();
            // 自动组卷
            var selectScore = addExamInput.SelectScore;
            var selectNum = addExamInput.SelectNum;
            var singScore = addExamInput.SingleScore;
            var singleNum = addExamInput.SingleNum;
            var judeScore = addExamInput.JudgeScore;
            var judgeNum = addExamInput.JudgeNum;
            // 全部多选题数据
            var allSelect = await _selectService.FindSelectListByCourseId(addExamInput.CourseId);
            // 全部单选题数据
            var allSingle = await _selectService.FindSingleListByCourseId(addExamInput.CourseId);
            // 全部是非题数据
            var allJudge = await _judgeService.FindJudgeListByCourseId(addExamInput.CourseId);
            // 蓄水池算法
            var randSelect = RandomUtil.Sampling<SelectDto>(allSelect, selectNum);
            var randSingle = RandomUtil.Sampling<SelectDto>(allSingle, singleNum);
            var randJudge = RandomUtil.Sampling<JudgeDto>(allJudge, judgeNum);
            // 判断题目题库是否足够
            if (randSelect.Count < selectNum)
            {
                throw Oops.Oh(ExamErrorCodes.s1902);
            }

            if (randSingle.Count < singleNum)
            {
                throw Oops.Oh(ExamErrorCodes.s1903);
            }

            if (randJudge.Count < judgeNum)
            {
                throw Oops.Oh(ExamErrorCodes.s1904);
            }
            addExamDto.ExamScore = 0;
            addExamDto.SelectScore = 0;
            addExamDto.SingleScore = 0;
            addExamDto.JudgeScore = 0;
            foreach (var item in randSelect)
            {
                var q = new ExamquestionDto();
                q.QuestionType = QuestionTypeConst.Select;
                q.QuestionId = item.Id;
                q.Score = selectScore;
                q.Select = item;
                questions.Add(q);
                addExamDto.SelectScore += selectScore;
                addExamDto.ExamScore += selectScore;
            }
            foreach (var item in randSingle)
            {
                var q = new ExamquestionDto();
                q.QuestionType = QuestionTypeConst.Single;
                q.QuestionId = item.Id;
                q.Score = singScore;
                q.Single = item;
                questions.Add(q);
                addExamDto.SingleScore += singScore;
                addExamDto.ExamScore += singScore;
            }
            foreach (var item in randJudge)
            {
                var q = new ExamquestionDto();
                q.QuestionType = QuestionTypeConst.Judge;
                q.QuestionId = item.Id;
                q.Score = judeScore;
                q.Judge = item;
                questions.Add(q);
                addExamDto.JudgeScore += judeScore;
                addExamDto.ExamScore += judeScore;
            }
            addExamDto.Examquestions = questions;
            var exam = await _examService.CreateExam(addExamDto);
            return exam.Adapt<ExamOutput>();
        }

        /// <summary>
        /// 更新试卷
        /// </summary>
        /// <param name="addExamInput"></param>
        /// <returns></returns>
        public async Task<ExamOutput> UpdateEditExam(EditExamInput editExamInput)
        {
            var teacher = await GetTeacher();
            var addExamDto = editExamInput.Adapt<ExamDto>();
            addExamDto.TeacherId = teacher.Id;
            var questions = new List<ExamquestionDto>();
            foreach (var item in editExamInput.Selects)
            {
                var q = item.Adapt<ExamquestionDto>();
                q.QuestionType = QuestionTypeConst.Select;
                questions.Add(q);
            }

            foreach (var item in editExamInput.Singles)
            {
                var q = item.Adapt<ExamquestionDto>();
                q.QuestionType = QuestionTypeConst.Single;
                questions.Add(q);
            }

            foreach (var item in editExamInput.Judges)
            {
                var q = item.Adapt<ExamquestionDto>();
                q.QuestionType = QuestionTypeConst.Judge;
                questions.Add(q);
            }

            addExamDto.Examquestions = questions;
            var exam = await _examService.UpdateExam(addExamDto);
            return exam.Adapt<ExamOutput>();
        }

        /// <summary>
        /// 删除试卷
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<string> DeleteRemoveExam(int id)
        {
            await _examService.DeleteExam(id);
            return "success";
        }

        /// <summary>
        /// 查询考试列表
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public async Task<PagedList<ExamCourseOutput>> GetExamList(
            [FromQuery] int pageIndex = 1,
            [FromQuery] int pageSize = 10)
        {
            var teacher = await GetTeacher();
            var teacherId = teacher.Id;
            var exams = await _examService.FindExamAllByTeacherAndPage(teacherId, pageIndex, pageSize);
            return exams.Adapt<PagedList<ExamCourseOutput>>();
        }

        /// <summary>
        /// 查询考试信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ExamCourseOutput> GetExamInfo(int id)
        {
            var exams = await _examService.FindExamById(id);
            return exams.Adapt<ExamCourseOutput>();
        }

        /// <summary>
        /// 查询考试是非题列表
        /// </summary>
        /// <param name="id">考试id</param>
        /// <returns></returns>
        public async Task<List<ExamquestionOutput>> GetJudges(int id)
        {
            var judges = await _questionService.FindJudgeByExam(id);

            return judges.Adapt<List<ExamquestionOutput>>();
        }
        
        /// <summary>
        /// 查询考试多选题列表
        /// </summary>
        /// <param name="id">考试id</param>
        /// <returns></returns>
        public async Task<List<ExamquestionOutput>> GetSelects(int id)
        {
            var judges = await _questionService.FindSelectByExam(id);

            return judges.Adapt<List<ExamquestionOutput>>();
        }
        
        /// <summary>
        /// 查询考试单选题列表
        /// </summary>
        /// <param name="id">考试id</param>
        /// <returns></returns>
        public async Task<List<ExamquestionOutput>> GetSingles(int id)
        {
            var judges = await _questionService.FindSingleByExam(id);

            return judges.Adapt<List<ExamquestionOutput>>();
        }

    }
}